package edu.nyu.msis.parser;

//import java.util.Vector;

import edu.nyu.msis.ds.MachineInstruction;
import edu.nyu.msis.ds.Module;
import edu.nyu.msis.utilities.ManagedBuffer;
import edu.nyu.msis.ds.InstructionType;

public class SrcParser {
	SrcStates srcListState;
    Integer moduleSize,noMoreModuleSize;
    String variable,tempType;
    Integer opCode,address;
    ManagedBuffer managedBuffer;
    Module module;
    MachineInstruction tempInstruction;
    InstructionType tempInstructionType;
	
	/**
	 * 
	 */
	public SrcParser() {
		super();
		// TODO Auto-generated constructor stub
		srcListState = SrcStates.WHITE_SPACE_IN_BEGIN;
        moduleSize = 0;
        noMoreModuleSize = 0;
        variable = "";
        address = 0;
        module = null;
        managedBuffer = new ManagedBuffer();
        tempInstruction = null;        
	}

    public void setModule(Module module) {
        this.module = module;
     }

	public ParserStates parse(Character readChar) {
        switch (srcListState) {
            case WHITE_SPACE_IN_BEGIN:
                {
                    if (Character.isWhitespace(readChar)) {
                        srcListState = SrcStates.WHITE_SPACE_IN_BEGIN;
                    }
                    else if (Character.isDigit(readChar)) {
                    	managedBuffer.addCharToBuffer(readChar);
                        srcListState = SrcStates.Get_MODULE_SIZE;
                    }
                    else if (Character.isLetter(readChar)) {
                        return ParserStates.ERROR_STATE;
                    }
                    else {
                        return ParserStates.ERROR_STATE;
                    }
                    return ParserStates.SRC_BEGIN;
                }
            case Get_MODULE_SIZE:
                {
                    if (Character.isWhitespace(readChar)) {
                        moduleSize = managedBuffer.convertBuffToInt();
                        module.setSize(moduleSize);
                        noMoreModuleSize = moduleSize;
                        srcListState = SrcStates.GOT_MODULE_SIZE;
                    }
                    else if (Character.isDigit(readChar)) {
                        managedBuffer.addCharToBuffer(readChar);
                        srcListState = SrcStates.Get_MODULE_SIZE;
                    }
                    else if (Character.isLetter(readChar)) {
                        return ParserStates.ERROR_STATE;
                    }
                    else {
                        return ParserStates.ERROR_STATE;
                    }
                    return ParserStates.SRC_BEGIN;
                }
            case GOT_MODULE_SIZE:
                {
                    if (Character.isWhitespace(readChar)) {
                        srcListState = SrcStates.GOT_MODULE_SIZE;
                    }
                    else if (Character.isDigit(readChar)) {
                        return ParserStates.ERROR_STATE;
                    }
                    else if (Character.isLetter(readChar)){
                    	managedBuffer.addCharToBuffer(readChar);
                        srcListState = SrcStates.GET_INSTRUCTION_TYPE;
                    }
                    else {
                        return ParserStates.ERROR_STATE;
                    }
                    return ParserStates.SRC_BEGIN;
                }
            case GET_INSTRUCTION_TYPE:
                {
                    if (Character.isWhitespace(readChar)) {
                        tempType = managedBuffer.convertBuffToString();
                        if(tempType.equals("E"))
                        	tempInstructionType = InstructionType.EXTERNAL;
                        else if(tempType.equals("I"))
                        	tempInstructionType = InstructionType.IMMEDIATE;
                        else if(tempType.equals("A"))
                        	tempInstructionType = InstructionType.ABSOLUTE;
                        else if(tempType.equals("R"))
                        	tempInstructionType = InstructionType.RELATIVE;
                        noMoreModuleSize--;
                        srcListState = SrcStates.GOT_INSTRUCTION_TYPE;
                    }
                    else {
                        return ParserStates.ERROR_STATE;
                    }
                    return ParserStates.SRC_BEGIN;
                }
            case GOT_INSTRUCTION_TYPE:
            {
                if (Character.isWhitespace(readChar)) {
                    srcListState = SrcStates.GOT_INSTRUCTION_TYPE;
                }
                else if (Character.isDigit(readChar)) {
                    srcListState = SrcStates.GET_OPCODE;
                    managedBuffer.addCharToBuffer(readChar);
                }
                else if (Character.isLetter(readChar)) {
                	return ParserStates.ERROR_STATE;                 
                }
                else {
                    return ParserStates.ERROR_STATE;
                }
                return ParserStates.SRC_BEGIN;
            }
            case GET_OPCODE:
            {
            	opCode = managedBuffer.convertBuffToInt();
            	
            	if (Character.isDigit(readChar)){
            		managedBuffer.addCharToBuffer(readChar); 
            		srcListState = SrcStates.GOT_OPCODE; 
            	}   
            	else {
                    return ParserStates.ERROR_STATE;
                }
            	  return ParserStates.SRC_BEGIN;  
            }
            case GOT_OPCODE:
                {
                	if (Character.isWhitespace(readChar) || readChar == '\0') { //in case of end of string or file
    	                address = managedBuffer.convertBuffToInt();
    	                tempInstruction = new MachineInstruction(tempInstructionType,opCode,address);
    	                module.insertInstruction(tempInstruction);
    	                if (noMoreModuleSize== 0) {
                            return ParserStates.MODULE_END;
                        }
                        else {
                                srcListState = SrcStates.GOT_MODULE_SIZE;
                            return ParserStates.SRC_BEGIN;
                        }
                	}    	             
    	             else if (Character.isDigit(readChar)){
                		managedBuffer.addCharToBuffer(readChar);  
                		srcListState = SrcStates.GOT_OPCODE;
                	}   
                	else {
                        return ParserStates.ERROR_STATE;
                    }
                	
                    return ParserStates.SRC_BEGIN;
                }
          default:  //Should never reach here.
                {
                    System.out.println("Invalid DefListParser State [state: " + srcListState + ", read: " + readChar + "].");
                    return ParserStates.ERROR_STATE;
                }
        }
	}

    public void reset() {
		srcListState = SrcStates.WHITE_SPACE_IN_BEGIN;
		moduleSize = 0;
        noMoreModuleSize = 0;
        variable = "";
        address = 0;
        opCode = 0;
    }
}